package io.terminus.paas.profiler.utils.sync

import com.alibaba.dubbo.common.Constants
import com.alibaba.dubbo.common.URL
import com.alibaba.dubbo.common.utils.StringUtils
import io.terminus.paas.profiler.model.Configuration
import io.terminus.paas.profiler.model.DubboProvider
import io.terminus.paas.profiler.model.Route
import io.terminus.paas.profiler.model.Consumer
import java.util.*

/**
 * Created by gengrong on 16/3/16.
 */
object SyncUtils {

    val SERVICE_FILTER_KEY = ".service"

    val ADDRESS_FILTER_KEY = ".address"

    fun url2Provider(pair: Map.Entry<Long, URL?>?): DubboProvider? {
        pair ?: return null
        val id = pair.key
        val url = pair.value ?: return null
        val p = DubboProvider()

        p.address = url.address
        p.id = id
        p.service = url.serviceKey
        p.address = url.address
        p.application = url.getParameter(Constants.APPLICATION_KEY)
        p.url = url.toIdentityString()
        p.parameters = url.toParameterString()

        p.dynamic = url.getParameter("dynamic", true)
        p.enabled = url.getParameter(Constants.ENABLED_KEY, true)
        p.weight = url.getParameter(Constants.WEIGHT_KEY, Constants.DEFAULT_WEIGHT)
        p.username = url.getParameter("owner")
        return p
    }

    fun url2Configuration(pair: Map.Entry<Long, URL?>?): Configuration? {
        pair ?: return null
        val id = pair.key
        val url = pair.value ?: return null

        val c = Configuration()
        c.id = id

        val parameters = HashMap<String, String>(url.parameters)

        c.service = url.serviceKey
        parameters.remove(Constants.INTERFACE_KEY)
        parameters.remove(Constants.GROUP_KEY)
        parameters.remove(Constants.VERSION_KEY)
        parameters.remove(Constants.APPLICATION_KEY)
        parameters.remove(Constants.CATEGORY_KEY)
        parameters.remove(Constants.DYNAMIC_KEY)
        parameters.remove(Constants.ENABLED_KEY)
        c.enabled = url.getParameter(Constants.ENABLED_KEY, true)
        val host = url.host
        val anyhost = url.getParameter(Constants.ANYHOST_VALUE, false)
        if (!anyhost || "0.0.0.0" != host) {
            c.address = url.address
        }
        c.application = url.getParameter(Constants.APPLICATION_KEY, url.username)
        parameters.remove(Constants.VERSION_KEY)
        c.params = StringUtils.toQueryString(parameters)
        return c
    }

    fun url2OverrideList(cs: Map<Long, URL>?): List<Configuration> {
        val list = arrayListOf<Configuration>()
        if (cs == null) return list
        cs.entries.forEach {
            url2Configuration(it)?.let { c -> list.add(c) }
        }
        return list
    }

    fun filterFromService(urls: Map<String, Map<Long, URL>>?, filter: MutableMap<String, String>): Map<Long, URL> {
        val ret = HashMap<Long, URL>()
        if (urls == null) return ret

        val s = filter.remove(SERVICE_FILTER_KEY) as String
        if (s == null) {
            for (entry in urls.entries) {
                filterFromUrls(entry.value, ret, filter)
            }
        } else {
            val map = urls[s]
            filterFromUrls(map, ret, filter)
        }

        return ret
    }

    fun filterFromUrls(from: Map<Long, URL>?, to: MutableMap<Long, URL>, filter: Map<String, String>) {
        if (from == null || from.isEmpty()) return

        for (entry in from.entries) {
            val url = entry.value

            var match = true
            for ((key, value) in filter) {

                if (ADDRESS_FILTER_KEY == key) {
                    if (value != url.address) {
                        match = false
                        break
                    }
                } else {
                    if (value != url.getParameter(key)) {
                        match = false
                        break
                    }
                }
            }

            if (match) {
                to.put(entry.key, url)
            }
        }
    }

    fun <SM : Map<String, Map<Long, URL>>> filterFromCategory(urls: Map<String, SM>, filter: MutableMap<String, String>): Map<Long, URL> {
        val c = filter[Constants.CATEGORY_KEY] as String

        filter.remove(Constants.CATEGORY_KEY)
        return filterFromService(urls[c], filter)
    }

    fun <SM : Map<String, Map<Long, URL>>> filterFromCategory(urls: Map<String, SM>, category: String, id: Long): Map.Entry<Long, URL>? {
        val services = urls[category] ?: return null
        services.values.forEach {
            it.entries.forEach {
                if (id.equals(it.key))
                    return it
            }
        }
        return null
    }

    fun url2ConsumerList(cs: Map<Long, URL>?): List<Consumer> {
        val list = ArrayList<Consumer>()
        cs ?: return list
        cs.entries.forEach {
            url2Consumer(it)?.let { list.add(it) }
        }
        return list
    }

    fun url2Consumer(pair: Map.Entry<Long, URL?>?): Consumer? {
        pair ?: return null

        val id = pair.key
        val url = pair.value ?: return null

        val c = Consumer()
        c.id = id
        c.service = url.serviceKey
        c.address = url.host
        c.application = url.getParameter(Constants.APPLICATION_KEY)
        c.parameters = url.toParameterString()

        return c
    }

    fun url2Route(pair: Map.Entry<Long, URL>?): Route? {
        if (pair == null) {
            return null
        }

        val id = pair.key
        val url = pair.value

        val r = Route()
        r.id = (id)
        r.name = (url.getParameter("name"))
        r.service = (url.serviceKey)
        r.priority = (url.getParameter(Constants.PRIORITY_KEY, 0))
        r.enabled = (url.getParameter(Constants.ENABLED_KEY, true))
        r.force = (url.getParameter(Constants.FORCE_KEY, false))
        r.setRuleStr(url.getParameterAndDecoded(Constants.RULE_KEY))
        return r
    }

}
